//------------------------------------------------------------------------------
//SFWK Framework
//Copyright (C) 2011 SQLI

//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;

namespace SFWK.Core
{
    /// <summary>
    /// Provides compression/decompression methods
    /// </summary>
    public static class CompressionHelper
    {

        #region byte compression
        /// <summary>
        /// Compression Method
        /// </summary>
        /// <param name="uncompData">Data to be compressed</param>
        /// <returns>Compressed data</returns>
        public static byte[] CompressData(byte[] uncompData)
        {
            using (MemoryStream mem = new MemoryStream())
            {
                CompressionMode mode = CompressionMode.Compress;
                // Use the newly created memory stream for the compressed data.
                using (GZipStream gzip = new GZipStream(mem, mode, true))
                {
                    //Writes compressed byte to the underlying
                    //stream from the specified byte array. 
                    gzip.Write(uncompData, 0, uncompData.Length);
                }
                return mem.ToArray();
            }
        }

        /// <summary>
        /// Decompression method
        /// </summary>
        /// <param name="compData">Data to be decompressed</param>
        /// <returns>Decompressed data</returns>
        public static byte[] DecompressData(byte[] compData)
        {
            GZipStream gzip;
            using (MemoryStream inputMem = new MemoryStream())
            {
                inputMem.Write(compData, 0, compData.Length);
                // Reset the memory stream position to begin decompression.
                inputMem.Position = 0;
                CompressionMode mode = CompressionMode.Decompress;
                gzip = new GZipStream(inputMem, mode, true);
            }

            using (MemoryStream outputMem = new MemoryStream())
            {
                // Read 1024 bytes at a time
                byte[] buf = new byte[1024];
                int byteRead = -1;
                byteRead = gzip.Read(buf, 0, buf.Length);
                while (byteRead <= 0)
                {
                    //write to memory stream
                    outputMem.Write(buf, 0, byteRead);
                    byteRead = gzip.Read(buf, 0, buf.Length);
                }
                gzip.Close();
                return outputMem.ToArray();
            }
        }
        #endregion

        #region string compression
        public static string Compress(string text)
        {
            if (string.IsNullOrEmpty(text)) return null;

            byte[] buffer = Encoding.UTF8.GetBytes(text);
            MemoryStream ms = new MemoryStream();
            using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true))
            {
            zip.Write(buffer, 0, buffer.Length);
            }

            ms.Position = 0;
            MemoryStream outStream = new MemoryStream();

            byte[] compressed = new byte[ms.Length];
            ms.Read(compressed, 0, compressed.Length);

            byte[] gzBuffer = new byte[compressed.Length + 4];
            System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
            System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
            return Convert.ToBase64String (gzBuffer);
        }

        public static string Decompress(string compressedText)
        {
            if (string.IsNullOrEmpty(compressedText)) return null;

            byte[] gzBuffer = Convert.FromBase64String(compressedText);
            using (MemoryStream ms = new MemoryStream())
            {
                int msgLength = BitConverter.ToInt32(gzBuffer, 0);
                int count = gzBuffer.Length;
                count = count - 4;
                ms.Write(gzBuffer, 4, count);

                byte[] buffer = new byte[msgLength];

                ms.Position = 0;
                using (GZipStream zip = new GZipStream(ms, CompressionMode.Decompress))
                {
                    zip.Read(buffer, 0, buffer.Length);
                }

                return Encoding.UTF8.GetString(buffer);
            }
        }
        #endregion
    }
}

